﻿using CinemaMaestro.ViewModels;
using CinemaMaestro.WindowsApplication.EndPoints;
using MetroFramework;
using MetroFramework.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CinemaMaestro.WindowsApplication.Movie
{
    public partial class MoviesForm : MetroForm
    {
       private MovieEndPoints endPoints;
       private ActorEndPoints actorEndPoints;
       private DirectorEndPoints directorEndPoints;
       private CategoryEndPoints categoryEndpoints;

       private List<MovieViewModel> movies = new List<MovieViewModel>();

       private List<ActorViewModel> allActors = new List<ActorViewModel>();
       private List<ActorViewModel> actors = new List<ActorViewModel>();

       private List<DirectorViewModel> allDirectors = new List<DirectorViewModel>();
       private List<DirectorViewModel> directors = new List<DirectorViewModel>();

       private List<CategoryViewModel> allCategories = new List<CategoryViewModel>();
       private List<CategoryViewModel> categories = new List<CategoryViewModel>();

       private byte[] picture;
       private byte[] actorPicture;
       private byte[] directorPicture;

       public MoviesForm(HttpClient client)
        {
            this.endPoints = new MovieEndPoints(client);
            this.actorEndPoints = new ActorEndPoints(client);
            this.directorEndPoints = new DirectorEndPoints(client);
            this.categoryEndpoints = new CategoryEndPoints(client);

            InitializeComponent();

            PopulateMoviesListView();
            PopulateActorsComboBox();
            PopulateDirectorsComboBox();
            PopulateCategoriesComboBox();

            MoviesFormToInitialState();
            ActorsTabToInitialState();
            DirectorsTabToInitialState();
            CategoriesTabToInitialState();
        }    

        private void clearButton_Click(object sender, EventArgs e)
        {
            MoviesFormToInitialState();
            ActorsTabToInitialState();
            DirectorsTabToInitialState();
            CategoriesTabToInitialState();
        }

        private void MoviesFormToInitialState()
        {
            descriptionTextBox.Text = String.Empty;
            titleTextBox.Text = String.Empty;
            durationTextBox.Text = String.Empty;
            releaseDatePicker.Text = String.Empty;
            moviesListView.SelectedIndices.Clear();
            deleteButton.Enabled = false;
            updateButton.Enabled = false;
            createButton.Enabled = true;
            picture = null;
            pictureBox.Image = null;
            actors = new List<ActorViewModel>();
            actorsListView.Items.Clear();
            directors = new List<DirectorViewModel>();
            directorsListView.Items.Clear();
            categories = new List<CategoryViewModel>();
            categoriesListView.Items.Clear();
        }

        private async void PopulateMoviesListView()
        {
            moviesListView.Items.Clear();
            try
            {
                movies = await endPoints.GetAllMoviesAsync();
                foreach (var movie in movies)
                {
                    var item = new ListViewItem();
                    item.Text = movie.Id.ToString();
                    item.SubItems.Add(movie.Title);
                    item.SubItems.Add(movie.Duration.ToString());
                    item.SubItems.Add(movie.Description);
                    item.SubItems.Add(movie.ReleaseDate.ToShortDateString());
                    moviesListView.Items.Add(item);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve movies!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }           
        }


        private void moviesListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (moviesListView.SelectedItems.Count == 1)
            {
                deleteButton.Enabled = true;
                updateButton.Enabled = true;
                createButton.Enabled = false;
                picture = null;
                pictureBox.Image = null;

                titleTextBox.Text = moviesListView.SelectedItems[0].SubItems[1].Text;
                durationTextBox.Text = moviesListView.SelectedItems[0].SubItems[2].Text;
                descriptionTextBox.Text = moviesListView.SelectedItems[0].SubItems[3].Text;
                releaseDatePicker.Text = moviesListView.SelectedItems[0].SubItems[4].Text;

                int id = Int32.Parse(moviesListView.SelectedItems[0].SubItems[0].Text);
                picture = movies.First(x => x.Id == id).Image;
                UpdatePictureBox();
                actors = movies.First(x => x.Id == id).Actors.ToList();
                PopulateRelatedActorsListView();
                directors = movies.First(x => x.Id == id).Directors.ToList();
                PopulateRelatedDirectorsListView();
                categories = movies.First(x => x.Id == id).Categories.ToList();
                PopulateRelatedCategoriesListView();
            }
        }

        private void MoviesForm_MouseDown(object sender, MouseEventArgs e)
        {
            MoviesFormToInitialState();
            ActorsTabToInitialState();
            DirectorsTabToInitialState();
            CategoriesTabToInitialState();
        }

        private async void deleteButton_Click(object sender, EventArgs e)
        {
            try
            {
                int selectedId = Int32.Parse(moviesListView.SelectedItems[0].SubItems[0].Text);
                await endPoints.DeleteMovieAsync(selectedId);
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot delete movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
            finally
            {
                PopulateMoviesListView();
                MoviesFormToInitialState();
                ActorsTabToInitialState();
                DirectorsTabToInitialState();
                CategoriesTabToInitialState();
            }
        }

        private void browseButton_Click(object sender, EventArgs e)
        {
            if (pictureDialog.ShowDialog() == DialogResult.OK)
            {
                string filename = pictureDialog.FileName;
                picture = File.ReadAllBytes(filename);
                UpdatePictureBox();
            }
        }

        private void UpdatePictureBox()
        {
            Bitmap image;
            using (MemoryStream stream = new MemoryStream(picture))
            {
                image = new Bitmap(stream);
            }
            pictureBox.Image = image;
        }

        private void UpdateActorPictureBox()
        {
            Bitmap image;
            using (MemoryStream stream = new MemoryStream(actorPicture))
            {
                image = new Bitmap(stream);
            }
            actorPictureBox.Image = image;
        }

        private void UpdateDirectorPictureBox()
        {
            Bitmap image;
            using (MemoryStream stream = new MemoryStream(directorPicture))
            {
                image = new Bitmap(stream);
            }
            directorPictureBox.Image = image;
        }

        private async void createButton_Click(object sender, EventArgs e)
        {
            if (ValidateMovie())
            {
                try
                {
                    var movie = new MovieViewModel
                    {
                        Title = titleTextBox.Text,
                        Duration = Int32.Parse(durationTextBox.Text),
                        Description = descriptionTextBox.Text,
                        ReleaseDate = releaseDatePicker.Value,
                        Image = picture,
                        Actors = actors,
                        Directors = directors,
                        Categories = categories
                    };
                    await endPoints.CreateMovieAsync(movie);
                }
                catch
                {
                    MetroMessageBox.Show(this, "Cannot create movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }
                finally
                {
                    PopulateMoviesListView();
                    MoviesFormToInitialState();
                    ActorsTabToInitialState();
                    DirectorsTabToInitialState();
                    CategoriesTabToInitialState();
                }    
            }                      
        }

        private bool ValidateMovie()
        {
            if (titleTextBox.Text == String.Empty)
            {
                MetroMessageBox.Show(this, "Please provide a title for the Movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            } 
            if (durationTextBox.Text == String.Empty)
            {
                MetroMessageBox.Show(this, "Please provide a duration in minutes for the Movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }
            if (descriptionTextBox.Text == String.Empty)
            {
                MetroMessageBox.Show(this, "Please provide a description for the Movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }
            if (picture == null)
            {
                MetroMessageBox.Show(this, "Please select a picture for the Movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }
            return true;
        }

        private async void updateButton_Click(object sender, EventArgs e)
        {
            if (ValidateMovie())
            {
                try
                {
                    int selectedId = Int32.Parse(moviesListView.SelectedItems[0].SubItems[0].Text);
                    var movie = new MovieViewModel
                    {
                        Id = selectedId,
                        Title = titleTextBox.Text,
                        Duration = Int32.Parse(durationTextBox.Text),
                        Description = descriptionTextBox.Text,
                        ReleaseDate = releaseDatePicker.Value,
                        Image = picture,
                        Actors = actors,
                        Directors = directors,
                        Categories = categories
                    };
                    await endPoints.UpdateMovieAsync(movie);
                }
                catch
                {
                    MetroMessageBox.Show(this, "Cannot update movie!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }
                finally
                {
                    PopulateMoviesListView();
                    MoviesFormToInitialState();
                    ActorsTabToInitialState();
                    DirectorsTabToInitialState();
                    CategoriesTabToInitialState();
                } 
            }
        }

        private void moviesTabPage_MouseDown(object sender, MouseEventArgs e)
        {
            MoviesFormToInitialState();
            ActorsTabToInitialState();
            DirectorsTabToInitialState();
            CategoriesTabToInitialState();
        }

        private void PopulateRelatedActorsListView()
        {
            actorsListView.Items.Clear();
            foreach (var actor in actors)
            {
                var item = new ListViewItem();
                item.Text = actor.Id.ToString();
                item.SubItems.Add(actor.FirstName);
                item.SubItems.Add(actor.LastName);
                item.SubItems.Add(actor.BirthDay.ToShortDateString());
                actorsListView.Items.Add(item);
            }
        }

        private void ActorsTabToInitialState()
        {
            actorsListView.SelectedIndices.Clear();
            addActorButton.Enabled = false;
            deleteActorButton.Enabled = false;
            actorComboBox.SelectedIndex = -1;
            actorPicture = null;
            actorPictureBox.Image = null;
        }

        private void actorsListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (actorsListView.SelectedItems.Count == 1)
            {
                deleteActorButton.Enabled = true;
                addActorButton.Enabled = false;
                
                actorPicture = null;
                actorPictureBox.Image = null;

                int id = Int32.Parse(actorsListView.SelectedItems[0].SubItems[0].Text);
                actorPicture = actors.First(x => x.Id == id).Image;
                UpdateActorPictureBox();
            }
        }

        private void actorTabPage_MouseDown(object sender, MouseEventArgs e)
        {
            ActorsTabToInitialState();
        }

        private async void PopulateActorsComboBox() {
            actorComboBox.Items.Clear();
            try
            {
                allActors = await actorEndPoints.GetAllActorsAsync();
                foreach (var actor in allActors)
                {
                    actorComboBox.Items.Add(actor);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve actors!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void actorComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (actorComboBox.SelectedIndex > -1)
            {
                addActorButton.Enabled = true;
            }
            else
            {
                addActorButton.Enabled = false;
            }
        }

        private void addActorButton_Click(object sender, EventArgs e)
        {
            var selected = (ActorViewModel)actorComboBox.SelectedItem;
            actors.Add(selected);
            var item = new ListViewItem();
            item.Text = selected.Id.ToString();
            item.SubItems.Add(selected.FirstName);
            item.SubItems.Add(selected.LastName);
            item.SubItems.Add(selected.BirthDay.ToShortDateString());
            actorsListView.Items.Add(item);
            ActorsTabToInitialState();
        }

        private void deleteActorButton_Click(object sender, EventArgs e)
        {
            int selectedId = Int32.Parse(actorsListView.SelectedItems[0].SubItems[0].Text);
            var selected = actors.First(x => x.Id == selectedId);
            actors.Remove(selected);
            PopulateRelatedActorsListView();
            ActorsTabToInitialState();
        }

        private void DirectorsTabToInitialState()
        {
            directorsListView.SelectedIndices.Clear();
            addDirectorButton.Enabled = false;
            deleteDirectorButton.Enabled = false;
            directorsComboBox.SelectedIndex = -1;
            directorPicture = null;
            directorPictureBox.Image = null;
        }

        private void PopulateRelatedDirectorsListView()
        {
            directorsListView.Items.Clear();
            foreach (var director in directors)
            {
                var item = new ListViewItem();
                item.Text = director.Id.ToString();
                item.SubItems.Add(director.FirstName);
                item.SubItems.Add(director.LastName);
                item.SubItems.Add(director.BirthDay.ToShortDateString());
                directorsListView.Items.Add(item);
            }
        }

        private void directorsListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (directorsListView.SelectedItems.Count == 1)
            {
                deleteDirectorButton.Enabled = true;
                addDirectorButton.Enabled = false;

                directorPicture = null;
                directorPictureBox.Image = null;

                int id = Int32.Parse(directorsListView.SelectedItems[0].SubItems[0].Text);
                directorPicture = directors.First(x => x.Id == id).Image;
                UpdateDirectorPictureBox();
            }
        }

        private void directorTabPage_MouseDown(object sender, MouseEventArgs e)
        {
            DirectorsTabToInitialState();
        }

        private async void PopulateDirectorsComboBox()
        {
            directorsComboBox.Items.Clear();
            try
            {
                allDirectors = await directorEndPoints.GetAllDirectorsAsync();
                foreach (var director in allDirectors)
                {
                    directorsComboBox.Items.Add(director);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve directors!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void directorsComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (directorsComboBox.SelectedIndex > -1)
            {
                addDirectorButton.Enabled = true;
            }
            else
            {
                addDirectorButton.Enabled = false;
            }
        }

        private void addDirectorButton_Click(object sender, EventArgs e)
        {
            var selected = (DirectorViewModel)directorsComboBox.SelectedItem;
            directors.Add(selected);
            var item = new ListViewItem();
            item.Text = selected.Id.ToString();
            item.SubItems.Add(selected.FirstName);
            item.SubItems.Add(selected.LastName);
            item.SubItems.Add(selected.BirthDay.ToShortDateString());
            directorsListView.Items.Add(item);
            DirectorsTabToInitialState();
        }

        private void deleteDirectorButton_Click(object sender, EventArgs e)
        {
            int selectedId = Int32.Parse(directorsListView.SelectedItems[0].SubItems[0].Text);
            var selected = directors.First(x => x.Id == selectedId);
            directors.Remove(selected);
            PopulateRelatedDirectorsListView();
            DirectorsTabToInitialState();
        }

        private void CategoriesTabToInitialState()
        {
            categoriesListView.SelectedIndices.Clear();
            addCategoryButton.Enabled = false;
            deleteCategoryButton.Enabled = false;
            categoriesComboBox.SelectedIndex = -1;
        }

        private void PopulateRelatedCategoriesListView()
        {
            categoriesListView.Items.Clear();
            foreach (var category in categories)
            {
                var item = new ListViewItem();
                item.Text = category.Id.ToString();
                item.SubItems.Add(category.Name);
                categoriesListView.Items.Add(item);
            }
        }

        private void categoriesListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (categoriesListView.SelectedItems.Count == 1)
            {
                deleteCategoryButton.Enabled = true;
                addCategoryButton.Enabled = false;
            }
        }

        private void categoriesTabPage_MouseDown(object sender, MouseEventArgs e)
        {
            CategoriesTabToInitialState();
        }

        private async void PopulateCategoriesComboBox()
        {
            categoriesComboBox.Items.Clear();
            try
            {
                allCategories = await categoryEndpoints.GetAllCategoriesAsync();
                foreach (var category in allCategories)
                {
                    categoriesComboBox.Items.Add(category);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve categories!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void categoriesComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (categoriesComboBox.SelectedIndex > -1)
            {
                addCategoryButton.Enabled = true;
            }
            else
            {
                addCategoryButton.Enabled = false;
            }
        }

        private void addCategoryButton_Click(object sender, EventArgs e)
        {
            var selected = (CategoryViewModel)categoriesComboBox.SelectedItem;
            categories.Add(selected);
            var item = new ListViewItem();
            item.Text = selected.Id.ToString();
            item.SubItems.Add(selected.Name);
            categoriesListView.Items.Add(item);
            CategoriesTabToInitialState();
        }

        private void deleteCategoryButton_Click(object sender, EventArgs e)
        {
            int selectedId = Int32.Parse(categoriesListView.SelectedItems[0].SubItems[0].Text);
            var selected = categories.First(x => x.Id == selectedId);
            categories.Remove(selected);
            PopulateRelatedCategoriesListView();
            CategoriesTabToInitialState();
        }

    }
}
